// i.d(t, { M: () => Matrix })

import * as THREE from "three"

class ROMatrix {
  static identity: number[]
  elements: number[]
  constructor(e?: any) {
    this.elements = []
    e
      ? e.elements
        ? (this.elements = e.elements.slice())
        : THREE.Matrix4.prototype.set.apply(this, e)
      : THREE.Matrix4.prototype.set.apply(this, ROMatrix.identity as any)
  }
  equals(e: any) {
    return THREE.Matrix4.prototype.equals.call(this, e)
  }
  clone() {
    return new ROMatrix(this)
  }
}
ROMatrix.identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
export default class Matrix extends ROMatrix {
  threeMatrix: THREE.Matrix4
  constructor(e?: number[]) {
    Array.isArray(e) ? super(e) : super()
    this.threeMatrix = new THREE.Matrix4()
  }
  set(e: any, t: any, i: any, s: any, r: any, o: any, a: any, l: any, c: any, h: any, d: any, u: any, p: any, m: any, g: any, f: any) {
    THREE.Matrix4.prototype.set.call(this, e, t, i, s, r, o, a, l, c, h, d, u, p, m, g, f)
    return this
  }
  makeScale(x: number, y: number, z: number) {
    THREE.Matrix4.prototype.makeScale.call(this, x, y, z)
    return this
  }
  copy(e: Matrix) {
    for (let t = 0; t < this.elements.length; t++) this.elements[t] = e.elements[t]
    return this
  }
  clone() {
    return new Matrix().copy(this)
  }
  transpose(): THREE.Matrix4 {
    return THREE.Matrix4.prototype.transpose.call(this)
  }
  lookAt(eye: THREE.Vector3, target: THREE.Vector3, up: THREE.Vector3) {
    THREE.Matrix4.prototype.lookAt.call(this, eye, target, up)
    return this
  }
  setPosition(e: THREE.Vector3) {
    THREE.Matrix4.prototype.setPosition.call(this, e.x, e.y, e.z)
    return this
  }
  extractRotation(e: any) {
    THREE.Matrix4.prototype.extractRotation.call(this, e)
    return this
  }
  makePerspective(left: number, right: number, bottom: number, top: number, near: number, far: number) {
    //@ts-ignore
    THREE.Matrix4.prototype.makePerspective.call(this, left, right, bottom, top, near, far)
    return this
  }
  makePerspectiveFov(e: number, t: number, near = 0.1, far = 1000) {
    const bottom = near * Math.tan((e * (Math.PI / 180)) / 2),
      top = -bottom,
      right = bottom * t,
      left = -right
    //@ts-ignore
    return THREE.Matrix4.prototype.makePerspective.call(this, left, right, bottom, top, near, far), this
  }
  makeOrthographic(left: number, right: number, top: number, bottom: number, near: number, far: number) {
    THREE.Matrix4.prototype.makeOrthographic.call(this, left, right, top, bottom, near, far)
    return this
  }
  identity() {
    //@ts-ignore
    this.set.apply(this, ROMatrix.identity)
    return this
  }
  makeRotationFromQuaternion(q: THREE.Quaternion) {
    THREE.Matrix4.prototype.makeRotationFromQuaternion.call(this, q)
    return this
  }
  makeRotationFromEuler(euler: THREE.Euler) {
    THREE.Matrix4.prototype.makeRotationFromEuler.call(this, euler)
    return this
  }
  getInverse(e: Matrix) {
    THREE.Matrix4.prototype.copy.call(this, e as any)
    THREE.Matrix4.prototype.invert.call(this)
    return this
  }
  premultiply(e: Matrix) {
    THREE.Matrix4.prototype.premultiply.call(this, e as any)
    return this
  }
  multiplyMatrices(e: Matrix, t: Matrix) {
    THREE.Matrix4.prototype.multiplyMatrices.call(this, e as any, t as any)
    return this
  }
  scale(e: THREE.Vector3) {
    THREE.Matrix4.prototype.scale.call(this, e)
    return this
  }
  compose(translation: THREE.Vector3, rotation: THREE.Quaternion, scale: THREE.Vector3) {
    THREE.Matrix4.prototype.compose.call(this, translation, rotation, scale)
    return this
  }
  asThreeMatrix4() {
    return this.threeMatrix.set(
      this.elements[0],
      this.elements[4],
      this.elements[8],
      this.elements[12],
      this.elements[1],
      this.elements[5],
      this.elements[9],
      this.elements[13],
      this.elements[2],
      this.elements[6],
      this.elements[10],
      this.elements[14],
      this.elements[3],
      this.elements[7],
      this.elements[11],
      this.elements[15]
    )
  }
}
